package com.gitee.loyo.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import com.gitee.loyo.Request;
import com.gitee.loyo.Result;
import com.gitee.loyo.TokenManager;
import com.gitee.loyo.config.ChargeProperties;
import com.gitee.loyo.data.Token;
import com.gitee.loyo.err.QueryTokenFailureException;
import com.gitee.loyo.post.QueryTokenPost;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@RequiredArgsConstructor
public class RedisTokenManager implements TokenManager {
    private final String KEY = "__TCEC:Token";
    protected final ChargeProperties chargeProperties;
    protected final OkHttpHelper okHttpHelper;
    @Resource
    RedisTemplate<String, Object> redisTemplate;

    @Override
    public Token getToken() {
        try {
            return (Token) redisTemplate.opsForValue().get(KEY);
        }catch (Exception e){
            log.error("getToken error", e);
            return null;
        }
    }

    @Override
    public void saveToken(Token token) {
        redisTemplate.opsForValue().set(KEY, token, Duration.ofSeconds(token.getTokenAvailableTime()));
    }

    @SneakyThrows
    @Override
    public Token queryToken(){
        String url = builderUrl("query_token");
        QueryTokenPost post = new QueryTokenPost();
        post.setOperatorId(chargeProperties.getOperatorId());
        post.setOperatorSecret(chargeProperties.getOperatorSecret());
        Result<Token> tokenResult = (Result<Token>) okHttpHelper.post(url, new Request<>(chargeProperties.getOperatorId(), post), null, new TypeReference<Result<Token>>(){}.getType());
        if(tokenResult.getRet() != 0 || tokenResult.getData() == null){
            log.error("query_token error, Ret: " + tokenResult.getRet()
                + ", Msg: " + tokenResult.getMsg());
            throw new QueryTokenFailureException(tokenResult);
        }
        return tokenResult.getData();
    }

    @Scheduled(fixedDelay = 60 * 1000)
    protected void checkTokenEveryMinute(){
        try{
            Long tokenExpire = redisTemplate.getExpire(KEY, TimeUnit.SECONDS);
            if(tokenExpire <= 60){
                Token newToken = queryToken();
                saveToken(newToken);
            }
        }catch (Exception e){
            log.error("checkTokenEveryMinute error", e);
        }
    }

    private String builderUrl(String apiName){
        return chargeProperties.getUrl().endsWith("/") ? chargeProperties.getUrl() + apiName
            : chargeProperties.getUrl() + "/" + apiName;
    }
}
